`include "../codigo/MemController.v"
`include "Ram.v"

module TMemController();

    // Fetch
	reg	if_mc_en;
	reg [31:0] if_mc_addr;
	wire [31:0] mc_if_data;

	// Memory
	reg	mem_mc_rw;
	reg	mem_mc_en;
	reg [31:0] mem_mc_addr;
	wire [31:0] mem_mc_data;
	reg	mem_mc_en1h;
	reg	mem_mc_en1l;
	reg	mem_mc_en2h;
	reg	mem_mc_en2l;
	
    // Ram
	wire [31:0] mc_ram_addr;
	wire mc_ram_rw;
	wire mc_ram_en1h;
	wire [7:0] mc_ram_data1h;
	wire mc_ram_en1l;
	wire [7:0] mc_ram_data1l;
	wire mc_ram_en2h;
	wire [7:0] mc_ram_data2h;
	wire mc_ram_en2l;
	wire [7:0] mc_ram_data2l;

    // Additional registers
    reg clock;
    reg reset;
    reg [31:0] aux_mem_mc_data;

    // Configura o mem_mc_data com o dispositivo externo
    assign mem_mc_data[31:24] = (!if_mc_en && !mem_mc_rw && mem_mc_en) ? 8'bz : aux_mem_mc_data[31:24];
    assign mem_mc_data[23:16] = (!if_mc_en && !mem_mc_rw && mem_mc_en) ? 8'bz : aux_mem_mc_data[23:16];
    assign mem_mc_data[15:8] = (!if_mc_en && !mem_mc_rw && mem_mc_en) ? 8'bz : aux_mem_mc_data[15:8];
    assign mem_mc_data[7:0] = (!if_mc_en && !mem_mc_rw && mem_mc_en) ? 8'bz : aux_mem_mc_data[7:0];
    
    // Loads up the memory controller
   	MemController MemC(if_mc_en,
		if_mc_addr,
		mc_if_data,
	    mem_mc_rw,
    	mem_mc_en,
	 	mem_mc_addr,
	 	mem_mc_data,
		mem_mc_en1h,
		mem_mc_en1l,
		mem_mc_en2h,
		mem_mc_en2l,
	 	mc_ram_addr,
		mc_ram_rw,
		mc_ram_en1h,
	 	mc_ram_data1h,
		mc_ram_en1l,
	 	mc_ram_data1l,
		mc_ram_en2h,
	 	mc_ram_data2h,
		mc_ram_en2l,
	 	mc_ram_data2l);


    Ram RamC(clock,
        reset,
        mc_ram_addr,
        mc_ram_rw,
        mc_ram_en1h,
        mc_ram_data1h,
        mc_ram_en1l,
        mc_ram_data1l,
        mc_ram_en2h,
        mc_ram_data2h,
        mc_ram_en2l,
        mc_ram_data2l );


    always begin

        #5 clock = ~clock;

    end


    // Calls up the tasks designed to test the registers
    initial begin

        reset <= #0 1'b1;
        clock <= #0 1'b0;
        #5;

        // Instruction fetch
        $display("-----------------------------------------------------------------");
        $display(">>> Tenta ler instrucoes com o enable desabilitado:");
        if_mc_en <= #0 1'b0;
        if_mc_addr <= #0 32'b100;
        mem_mc_en <= #0 1'b0;
        #1 test_if;
        
        $display("------------------------------------------------------------------");
        $display(">>> Tenta ler instrucoes com o enable habilitado:");
        if_mc_en <= #0 1'b1;
        if_mc_addr <= #0 32'b100;
        mem_mc_en <= #0 1'b0;        
        #1 test_if;

        #2;

        // ----------------------------------------------------------
        $display("-----------------------------------------------------------------");
        $display(">>> Tenta escrever dado na RAM com enable habilitado, e com\napenas os dois bytes iniciais habilitados para escrita:");
        if_mc_en <= #0 1'b0;
        mem_mc_en <= #0 1'b1;
        mem_mc_rw <= #0 1'b1;
        mem_mc_en1h <= #0 1'b1;
        mem_mc_en1l <= #0 1'b0;
        mem_mc_en2h <= #0 1'b1;
        mem_mc_en2l <= #0 1'b0;
        mem_mc_addr <= #0 32'b100;
        aux_mem_mc_data <= #0 32'hFFFFFFFF;
        #1 test_mem;

        $display("-----------------------------------------------------------------");
        $display(">>> Tenta ler dado da RAM com enable habilitado para leitura,\ne com todos os bytes tambem habilitados:");
        if_mc_en <= #0 1'b0;
        mem_mc_en <= #0 1'b1;
        mem_mc_rw <= #0 1'b0;
        mem_mc_en1h <= #0 1'b1;
        mem_mc_en1l <= #0 1'b1;
        mem_mc_en2h <= #0 1'b1;
        mem_mc_en2l <= #0 1'b1;
        mem_mc_addr <= #0 32'b100;
        #1 test_mem;


        // ----------------------------------------------------------
        $display("-----------------------------------------------------------------");
        $display(">>> Tenta ler instrucoes com o enable desabilitado:");
        if_mc_en <= #0 1'b0;
        if_mc_addr <= #0 32'b100;
        mem_mc_en <= #0 1'b0;
        #1 test_if;

        $display("-----------------------------------------------------------------");
        $display(">>> Tenta ler instrucoes com o enable habilitado:");
        if_mc_en <= #0 1'b1;
        if_mc_addr <= #0 32'b100;
        mem_mc_en <= #0 1'b0;
        #1 test_if;       


        // ----------------------------------------------------------
        $display("-----------------------------------------------------------------");
        $display(">>> Escreve novo dado na RAM:");
        if_mc_en <= #0 1'b0;
        mem_mc_en <= #0 1'b1;
        mem_mc_rw <= #0 1'b1;
        mem_mc_en1h <= #0 1'b1;
        mem_mc_en1l <= #0 1'b1;
        mem_mc_en2h <= #0 1'b1;
        mem_mc_en2l <= #0 1'b1;
        mem_mc_addr <= #0 32'b100;
        aux_mem_mc_data <= #0 32'hF0F0F0F0;
        #1 test_mem;
        #6;

        
        $display("-----------------------------------------------------------------");
        $display(">>> Alterando o valor do registrador auxiliar:");
        aux_mem_mc_data <= #0 32'h00FFFF00;
        #1 $display("    aux_mem_mc_data: %b\n", aux_mem_mc_data);
        


        $display("-----------------------------------------------------------------");
        $display(">>> Instruction fetch tem prioridade quando os dois sinais\nestão habilitados:");
        if_mc_en <= #0 1'b1;
        if_mc_addr <= #0 32'b100;
        mem_mc_en <= #0 1'b1;
        mem_mc_rw <= #0 1'b1;

        // Informacoes 
        #1 test_if;
        #0 test_mem;
        #10;


        $display("-----------------------------------------------------------------");
        $display(">>> Memoria nao foi escrita pois o instruction fetch tem prioridade:"); 
        if_mc_en <= #0 1'b0;
        mem_mc_rw <= #0 1'b0;
        #10;


        #0 test_if;
        #0 test_mem;


        #10 $finish;
   
    end


    // --------------------------------------------------------------
    // Instruction fetch test
    task test_if; begin
        
        $display("    if_mc_en: %d", if_mc_en);
        $display("    if_mc_addr: %d", if_mc_addr);
        $display("    mc_if_data: %b", mc_if_data);
        $display("    mem_mc_en: %d\n", mem_mc_en);
       
    end
    endtask

    

    // --------------------------------------------------------------
    // Memory reading test
    task test_mem; begin

        $display("    mem_mc_addr: %d", mem_mc_addr);
        $display("    aux_mem_mc_data: %b", aux_mem_mc_data);
        $display("    mem_mc_data: %b", mem_mc_data);
        $display("    mem_mc_rw: %b", mem_mc_rw);
        $display("    mem_mc_en: %b", mem_mc_en);
        $display("    mem_mc_en1h: %b", mem_mc_en1h);
        $display("    mem_mc_en1l: %b", mem_mc_en1l);
        $display("    mem_mc_en2h: %b", mem_mc_en2h);
        $display("    mem_mc_en2l:%b\n", mem_mc_en2l);
        
    end
    endtask


endmodule
